Computing systems generally use an operating system to provide system resource management for various software applications that may execute in the computing system. The operating system itself typically employs a kernel and a set of libraries and/or utilities. The kernel includes the most basic (and necessary) operating system functions and data structures (such as a task scheduler and I/O functions), while the libraries/utilities may include other functionality which is useful to applications (such as a network stack). In computing systems employing a flat, protectionless memory model, applications may access the operating system functions and data structures by linking to the memory locations associated with the desired function/data structure and directly accessing the memory locations associated with the desired function/data structure at run time.
In order to protect the integrity of the operating system during the execution of application software—for example, during debugging—operating systems may employ a memory protection scheme that shields critical operating system-related memory areas from access. For example, memory space for kernel functions and data structures may be logically isolated from memory space in which application functions and data structures are stored. Memory access to kernel memory space may be further restricted through the use of a Memory Management Unit (MMU) that restricts memory accesses to protected memory areas. In addition, some microprocessors provide for multiple “modes” of operation—for example, a “user” mode for the execution of applications and other non-trusted software, and a “supervisor” mode for the execution of kernel functions and other trusted software.
In order to allow applications to use kernel facilities in systems which use a memory protection scheme, special “system call” procedures have been implemented. For example, in some operating systems, all accesses to kernel memory space are performed indirectly via an interrupt request to specified interrupt numbers (using, for example, and “INT xx” processor instruction (sometimes called an “op code”), where the “xx” is the number of the interrupt), with parameters passed via specified registers or memory locations. The interrupt handler is used to invoke the desired kernel function, thus preventing the calling program from directly accessing the kernel. Another construct that has been used is an exception-based system call, which uses exceptions generated by a memory management unit (MMU) as a result of direct memory accesses to enforce the memory protection scheme. An advantage of the exception-based system call is that a special system call instruction is not needed, and therefore program code can invoke “system” functions and data (i.e., located in protected memory areas) in a fashion similar to that used to invoke “non-system” functions and data, as well as avoid the use of additional tasks to achieve such access.
The use of system calls in protected memory systems, however, introduces a significant amount of delay into system memory access. For example, the interrupt-based system call requires the generation of an interrupt, the execution of an interrupt handler to enable the system memory access, and perhaps the creation of a “system task” to perform the desired function/memory access. Even the exception-based system call requires the processing of the exception (although only when making an access to a protected memory region). Thus, in order to maximize execution speed, it is desirable to run applications using a protectionless memory system.
Developers have previously attempted to utilize memory protection schemes during application development. The protection scheme protects the operating system during the implementation phase and can be used to indicate programming errors (e.g., illegal modification of kernel data structures). Once the application has been tested and a degree of confidence in the application's trustworthiness has been determined, application designers remove the protection mechanisms, which heretofore required actually changing the program code to provide direct access to previously protected memory areas. Such changes not only were time-consuming, but introduced the possibility of introducing additional bugs into the application. Additionally, application developers have been limited to the single method of invoking system calls supported by the operating system, even where no protection was desired, or faster execution speed could be achieved using alternative system call techniques.